#include "doublelinkedlist.h"

void DoubleLinkedList_Init(List * l)
{
	l->first = NULL;
	l->last = NULL;
	l->count = 0;
}

void DoubleLinkedList_Copy(const List * source,List** destination)
{
	DoubleCell* c;
	if (!DoubleLinkedList_IsEmpty(source))
	{
		c = source->first;
		DoubleLinkedList_Init(*destination);
		while(c != NULL)
		{
			DoubleLinkedList_InsertLast(*destination,c->value);
			c = c->next;
		}
	}
}

int DoubleLinkedList_IsEmpty(const List * l)
{
	return (l->first == NULL);
}

DoubleCell* DoubleLinkedList_InsertAt(List* l, Element e, int position)
{
	unsigned int i; DoubleCell* c;
	if (position < l->count)
	{
		if(position < (l->count / 2))
		{
			c = l->first;
			for(i = 0; i < position; i++)
				c = c->next;
		}
		else
		{
			position = l->count - position;
			c = l->last;
			for(i = 0; i < position; i++)
				c = c->previous;
		}
		i = (unsigned int) c;
		c = (DoubleCell*) malloc(sizeof(DoubleCell));
		c->previous = (DoubleCell*)i;
		c->next = c->previous->next;
		c->next->previous = c;
		c->previous->next = c;
		l->count++;
		return c;
	}
	else
		return NULL;
}

DoubleCell* DoubleLinkedList_Insert(List* l, Element e, Element at)
{
	DoubleCell* c = (DoubleCell*) malloc(sizeof(DoubleCell));
	c->value = e;
	c->previous = DoubleLinkedList_Search(l,at);
	if(c->previous == NULL)
	{
		free(c);
		return NULL;
	}
	c->next = c->previous->next;
	c->previous->next = c;
	c->next->previous = c;
	l->count ++;
	return c;
}

void DoubleLinkedList_InsertLast(List* l,Element e)
{
	DoubleCell* c = (DoubleCell*) malloc(sizeof(DoubleCell));
	c->value = e;
	if(l->count == 0)
	{
		c->previous = NULL;
		c->next = NULL;
		l->first = c;
		l->last = c;
	}
	else
	{
		c->previous = l->last;
		c->next = NULL;
		l->last->next = c;
		l->last = c;
	}
	l->count++;
}

void DoubleLinkedList_InsertFirst(List* l,Element  e)
{
	DoubleCell* c = (DoubleCell*) malloc(sizeof(DoubleCell));
	c->value = e;
	if(l->count == 0)
	{
		c->previous = NULL;
		c->next = NULL;
		l->first = c;
		l->last = c;
	}
	else
	{
		c->previous = NULL;
		c->next = l->first;
		l->first->previous = c;
		l->first = c;
	}
	l->count++;
}

Element DoubleLinkedList_GetFirst(const List* l)
{
	return l->first->value;
}

Element DoubleLinkedList_GetLast(const List* l)
{
	return l->last->value;
}

Element DoubleLinkedList_ReadFirst(List* l)
{
	DoubleCell* c = l->first; Element e;
	if (l->count == 0)
		return NULL;
	e = l->first->value;
	if (l->count == 1)
	{
		l->first = NULL;
		l->last = NULL;
	}
	else
	{
		l->first = l->first->next;
		l->first->previous = NULL;
	}
	free(c);
	l->count--;
	return e;
}

Element DoubleLinkedList_ReadLast(List* l)
{
	DoubleCell* c = l->last; Element e;
	if (l->count == 0)
		return NULL;
	e = l->first->value;
	if (l->count == 1)
	{
		l->first = NULL;
		l->last = NULL;
	}
	else
	{
		l->last = l->last->previous;
		l->last->next = NULL;
	}
	free(c);
	l->count--;
	return e;
}

DoubleCell* DoubleLinkedList_Search(const List* l,Element e)
{
  DoubleCell* c = l->first;
  while(c->next!=NULL)
   {
    if(c->value==e)
     return c;
    c=c->next;
   }
  return NULL;
}

DoubleCell* DoubleLinkedList_SearchFromLast(const List* l,Element e)
{
  DoubleCell* c = l->last;
  while(c->previous!=NULL)
   {
    if(c->value==e)
     return c;
    c=c->previous;
   }
  return NULL;
}

void DoubleLinkedList_Destroy(List* l)
{
	while (l->first != NULL)
	{
		l->last = l->first;
		l->first = l->first->next;
		free(l->last);
	}
	l->first = NULL;
	l->last = NULL;
	l->count = 0;
}